package com.xm.xmwa1706090.service.netty;

import com.xm.xmwa1706090.service.model.SocketEntity;
import com.xm.xmwa1706090.service.util.CodeUtil;
import com.xm.xmwa1706090.service.util.HexCodeUtils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.List;

/**
 * @Company 杭州新苗网络科技有限公司
 * @Author : loysen
 * @DateTime：2017年4月22日 下午5:53:06
 * @Description : {消息解码类}
 *
 *
 */
public class    ServerSocketEntityDecoder extends ByteToMessageDecoder {

    Logger logger = LoggerFactory.getLogger(ServerSocketEntityDecoder.class);

    // private static final int BUFFER_SIZE = 1024;// 缓存大小
    byte[] recvBuf = null;// 接收消息的缓存
    private final static String start = "FAFA";// 包头标志
    private final static String end = "AFAF";// 结束标志

    int count = 0;// 接收消息的总大小
    byte[] byteMerger = new byte[0];// 接收消息byte数组合并
    int cutCount = 0;// 裁剪值 0:不裁剪 1:裁剪
    boolean deCodeSuccess = true; //
    int recvMsgSize = 0;// byte数组接收消息的大小


    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf bb, List<Object> out) {
        recvMsgSize = bb.readableBytes();
        recvBuf = new byte[recvMsgSize];
        bb.readBytes(recvBuf);
        count = recvMsgSize + count;
        byteMerger = CodeUtil.byteMerger(byteMerger, recvBuf, recvMsgSize);
        if (count < 32 ) {
            return;
        }
        // 判断是否已经读完;判断数据是否完整
        if (count >= 32 ) {
            // byte[]数组转为16进制字符串
            String recvData = CodeUtil.printHexString(byteMerger, count);
            System.out.println("recvMsgSize  :" + recvMsgSize + "  recvBuf :" + recvData);
            recvData = recvData.replace(" ", "");
            // 解析协议
            byteMerger = solveStickPackage(recvData, out, cutCount, deCodeSuccess);

            count = byteMerger.length;
            deCodeSuccess = true;
            cutCount = 0;
        }
        // 清空recvBuf
        recvBuf = null;
    }

    /**
     * @Author loysen
     * @Data_Time 2017年6月16日 上午10:21:23
     * @Description {字符串形式解析包协议}
     * @param data
     * @return
     * @throws IOException
     */
    public byte[] decodeStrData(String data, List<Object> out, int cutCount,  boolean deCodeSuccess) {
        // 协议格式：SocketEntity类
        data =data.substring( data.indexOf(start), data.indexOf(end)+8);
        System.out.println("SocketEntity类:"+data);
        SocketEntity entity = new SocketEntity();
        entity.setStart(data.substring(0,4));
        entity.setEnd( data.substring(data.length() - 8 ,data.length() -4 ) );
        // 检查包头标志： start
        // minLength = (2+2+2++2+2+2+12+4+4+2+2 )*2 = 64
        if (data.length() > 64 && start.equals(entity.getStart().toUpperCase())
                && end.equals(entity.getEnd().toUpperCase())    ) {
            entity.setLength(  Integer.valueOf(data.substring(4, 8),16).toString() );
            entity.setVersion(  Integer.valueOf(data.substring(8, 10),16).toString() +   Integer.valueOf(data.substring(10, 12),16).toString());
            entity.setCmd(  Integer.valueOf(data.substring(12, 16),16 ).toString() );
            entity.setType( Integer.valueOf(data.substring(16, 20),16 ).toString() );
            entity.setTermid(Integer.valueOf(data.substring(20, 44),16 ).toString() );
            entity.setSeq(Integer.valueOf(data.substring(44, 52),16 ).toString() );
            entity.setFlag(Integer.valueOf(data.substring(52, 60),16 ).toString() );
            entity.setParam(HexCodeUtils.hexStr2Str( data.substring(60,data.length()-8)  ));

            entity.setCrc16(   data.substring(data.length()-4, data.length() ) );
            // 索
            int index = 2 + 2 + Integer.valueOf(entity.getLength()) + 8 ;
            // 判断索引是否超出字符串长度
            if (index <= data.length()) {
                byte[] crc16_data = CodeUtil.hexStringToBytes(data.substring(0,60)+entity.getParam()+ data.substring(data.length()-8,data.length()-4));
                String crc16 = CodeUtil.CRC16Table(crc16_data);
                crc16 = crc16.substring(0, 4);


                // CRC校验，判断数据是否完整
                if (crc16.equals(entity.getCrc16())) {
                    // j校验通过，传递Entity
                    out.add(entity);
                    // 裁剪一个完整的包数据
                    // System.out.println("裁剪一个完整包前的data   :"+data);
                    logger.info("裁剪一个完整包前的data   :"+data);
                    data = data.substring(index, data.length());
                    // System.out.println("裁剪一个完整包后的data   :" + data);
                    logger.info("裁剪一个完整包后的data   :"+data);
                    cutCount = 0;
                    // 数据完整并且校验通过
                    logger.info("数据完整并且校验通过   :"+data);
                    System.out.println("数据完整并且校验通过   :"+data);
                    deCodeSuccess = true;
                } else {
                    // 数据长度足够，但CRC校验不通过
                    deCodeSuccess = false;
                }
            } else {
                // 数据长度不够
                deCodeSuccess = false;
            }
        } else {
            // 数据包标志格式不对
            deCodeSuccess = false;
        }
        // System.out.println("DeCode_Success   :"+DeCode_Success);
        return solveStickPackage(data, out, cutCount, deCodeSuccess);
    }

    /**
     * @Author loysen
     * @Data_Time 2017年4月2日 上午10:21:23
     * @Description {解决粘包，包不完整等问题}
     * @param data
     * @param out
     * @return
     * @throws IOException
     */
    public byte[] solveStickPackage(String data, List<Object> out,
                                      int cutCount, boolean deCodeSuccess) {
         System.out.println("开始解析 包数据： start ....  "+data);
        int headCount = CodeUtil.getContainStrCount(start, data);
        // System.out.println("HEAD_COUNT   :" + HEAD_COUNT);
        // 判断数据长度并且包含包头标志
        if (data.length() > 64 && headCount > 1) {
            data = data.substring(data.indexOf(start) + 4 * cutCount,  data.length());
            cutCount = 1;
            System.out.println("第二次裁剪后的data  ：" + data);
            return decodeStrData(data, out, cutCount, deCodeSuccess);
        } else if (data.length() > 0 && headCount < 1) {
            // data中没有包头标志，说明不是一个完整包，丢弃
            data = null;
            logger.info("data中没有包头标志，说明不是一个完整包，丢弃data");
            // System.out.println("data中没有包头标志，说明不是一个完整包，丢弃data");
            return new byte[0];
        } else if ( headCount > 0 ) {// 临界状态，只有一个包头标志，但数据不全等
            if (data.length() < 64 || !deCodeSuccess) {
                // data中包含包头标志，但数据不完全
                // System.out.println("data中包含包头标志，但数据不完全    data ： " + data);
                logger.info("data中包含包头标志，但数据不完全， data ： " + data);
                return CodeUtil.hexStringToBytes(data);
            } else {
                // data中包含包头标志，但不肯定数据是否完全，不完全时 DeCode_Success标志为：true
                // System.out.println("data中包含包头标志，但不肯定数据是否完全  data :  "+data);
                logger.info("data中包含包头标志，但不肯定数据是否完全  data :  "+data);
                return decodeStrData(data, out, cutCount, deCodeSuccess);
            }
        }
        return new byte[0];
    }




}
